;	skeletal cbios for first level of CP/M 2.0 alteration
;
msize	equ	20		;cp/m version memory size in kilobytes
;
;	"bias" is address offset from 3400h for memory systems
;	than 16k (referred to as"b" throughout the text)
;
bias	equ	(msize-20)*1024
ccp	equ	3400h+bias	;base of ccp
bdos	equ	ccp+806h	;base of bdos
bios	equ	ccp+1600h	;base of bios
cdisk	equ	0004h		;current disk number 0=a,... l5=p
iobyte	equ	0003h		;intel i/o byte
;
	org	bios		;origin of this program
nsects	equ	($-ccp)/128	;warm start sector count
;
;	jump vector for individual subroutines
;
	jmp	boot	;cold start
wboote:	jmp	wboot	;warm start
	jmp	const	;console status
	jmp	conin	;console character in
	jmp	conout	;console character out
	jmp	list	;list character out
	jmp	punch	;punch character out
	jmp	reader	;reader character out
	jmp	home	;move head to home position
	jmp	seldsk	;select disk
	jmp	settrk	;set track number
	jmp	setsec	;set sector number
	jmp	setdma	;set dma address
	jmp	read	;read disk
	jmp	write	;write disk
	jmp	listst	;return list status
	jmp	sectran	;sector translate
;
;	fixed data tables for four-drive standard
;	ibm-compatible 8" disks
;
;	disk Parameter header for disk 00
dpbase:	dw	trans, 0000h
	dw	0000h, 0000h
	dw	dirbf, dpblk
	dw	chk00, all00
;	disk parameter header for disk 01
	dw	trans, 0000h
	dw	0000h, 0000h
	dw	dirbf, dpblk
	dw	chk01, all01
;	disk parameter header for disk 02
	dw	trans, 0000h
	dw	0000h, 0000h
	dw	dirbf, dpblk
	dw	chk02, all02
;	disk parameter header for disk 03
	dw	trans, 0000h
	dw	0000h, 0000h
	dw	dirbf, dpblk
	dw	chk03, all03
;
;	sector translate vector
trans:	db	 1,  7, 13, 19	;sectors  1,  2,  3,  4
	db	25,  5, 11, 17	;sectors  5,  6,  7,  6
	db	23,  3,  9, 15	;sectors  9, 10, 11, 12
	db	21,  2,  8, 14	;sectors 13, 14, 15, 16
	db	20, 26,  6, 12	;sectors 17, 18, 19, 20
	db	18, 24,  4, 10	;sectors 21, 22, 23, 24
	db	16, 22		;sectors 25, 26
;
dpblk:	;disk parameter block, common to all disks
	dw	26		;sectors per track
	db	3		;block shift factor
	db	7		;block mask
	db	0		;null mask
	dw	242		;disk size-1
	dw	63		;directory max
	db	192		;alloc 0
	db	0		;alloc 1
	dw	16		;check size
	dw	2		;track offset
;
;	end of fixed tables
;
;	individual subroutines to perform each function
boot:	;simplest case is to just perform parameter initialization
	xra	a		;zero in the accum
	sta	iobyte		;clear the iobyte
	sta	cdisk		;select disk zero
	jmp	gocpm		;initialize and go to cp/m
;
wboot:	;simplest case is to read the disk until all sectors loaded
	lxi	sp, 80h		;use space below buffer for stack
	mvi	c, 0		;select disk 0
	call	seldsk
	call	home		;go to track 00
;
	mvi	b, nsects	;b counts * of sectors to load
	mvi	c, 0		;c has the current track number
	mvi	d, 2		;d has the next sector to read
;	note that we begin by reading track 0, sector 2 since sector 1
;	contains the cold start loader, which is skipped in a warm start
	lxi	h, ccp		;base of cp/m (initial load point)
load1:	;load	one more sector
	push	b		;save sector count, current track
	push	d		;save next sector to read
	push	h		;save dma address
	mov	c, d		;get sector address to register C
	call	setsec		;set sector address from register C
	pop	b		;recall dma address to b, C
	push	b		;replace on stack for later recall
	call	setdma		;set dma address from b, C
;
;	drive set to 0, track set, sector set, dma address set
	call	read
	cpi	00h		;any errors?
	jnz	wboot		;retry the entire boot if an error occurs
;
;	no error, move to next sector
	pop	h		;recall dma address
	lxi	d, 128		;dma=dma+128
	dad	d		;new dma address is in h, l
	pop	d		;recall sector address
	pop	b	;recall number of sectors remaining, and current trk
	dcr	b		;sectors=sectors-1
	jz	gocpm		;transfer to cp/m if all have been loaded
;
;	more	sectors remain to load, check for track change
	inr	d
	mov	a,d		;sector=27?, if so, change tracks
	cpi	27
	jc	load1		;carry generated if sector<27
;
;	end of	current track,	go to next track
	mvi	d, 1		;begin with first sector of next track
	inr	c		;track=track+1
;
;	save	register state, and change tracks
	push	b
	push	d
	push	h
	call	settrk		;track address set from register c
	pop	h
	pop	d
	pop	b
	jmp	load1		;for another sector
;
;	end of	load operation, set parameters and go to cp/m
gocpm:
	mvi	a, 0c3h		;c3 is a jmp instruction
	sta	0		;for jmp to wboot
	lxi	h, wboote	;wboot entry point
	shld	1		;set address field for jmp at 0
;
	sta	5		;for jmp to bdos
	lxi	h, bdos		;bdos entry point
	shld	6		;address field of Jump at 5 to bdos
;
	lxi	b, 80h		;default dma address is 80h
	call	setdma
;
	ei			;enable the interrupt system
	lda	cdisk		;get current disk number
	mov	c, a		;send to the ccp
	jmp	ccp		;go to cp/m for further processing
;
;
;	simple i/o handlers (must be filled in by user)
;	in each case, the entry point is provided, with space reserved
;	to insert your own code
;
const:	;console status, return 0ffh if character ready, 00h if not
	ds     10h		;space for status subroutine
	mvi    a, 00h
	ret
;
conin:	;console character into register a
	ds	10h		;space for input routine
	ani	7fh		;strip parity bit
	ret
;
conout:	;console character output from register c
	mov	a, c		;get to accumulator
	ds	10h		;space for output routine
	ret
;
list:	;list character from register c
	mov	a, c	  	;character to register a
	ret		  	;null subroutine
;
listst:	;return list status (0 if not ready, 1 if ready)
	xra	a	 	;0 is always ok to return
	ret
;
punch:	;punch	character from	register C
	mov	a, c		;character to register a
	ret			;null subroutine
;
;
reader:	;reader character into register a from reader device
	mvi    a, 1ah		;enter end of file for now (replace later)
	ani    7fh		;remember to strip parity bit
	ret
;
;
;	i/o drivers for the disk follow
;	for now, we will simply store the parameters away for use
;	in the read and write	subroutines
;
home:	;move to the track 00	position of current drive
;	translate this call into a settrk call with Parameter 00
	mvi    c, 0		;select track 0
	call   settrk
	ret			;we will move to 00 on first read/write
;
seldsk:	;select disk given by register c
	lxi	h, 0000h	;error return code
	mov	a, c
	sta	diskno
	cpi	4		;must be between 0 and 3
	rnc			;no carry if 4, 5,...
;	disk number is in the proper range
	ds	10		;space for disk select
;	compute proper disk Parameter header address
	lda	diskno
	mov	l, a		;l=disk number 0, 1, 2, 3
	mvi	h, 0		;high order zero
	dad	h		;*2
	dad	h		;*4
	dad	h		;*8
	dad	h		;*16 (size of each header)
	lxi	d, dpbase
	dad	0		;hl=,dpbase (diskno*16)
	ret
;
settrk:	;set track given by register c
	mov	a, c
	sta	track
	ds	10h		;space for track select
	ret
;
setsec:	;set sector given by register c
	mov	a, c
	sta	sector
	ds	10h		;space for sector select
	ret
;
;
sectran:
	;translate the sector given by bc using the
	;translate table given by de
	xchg			;hl=.trans
	dad	b		;hl=.trans (sector)
	mov	l, m		;l=trans (sector)
	mvi	h, 0		;hl=trans (sector)
	ret			;with value in hl
;
setdma:	;set	dma address given by registers b and c
	mov	l, c		;low order address
	mov	h, b		;high order address
	shld	dmaad		;save the address
	ds	10h		;space for setting the dma address
	ret
;
read:	;perform read operation (usually this is similar to write
;	so we will allow space to set up read command, then use
;	common code in write)
	ds	10h		;set up read command
	jmp	waitio		;to perform the actual i/o
;
write:	;perform a write operation
	ds	10h		;set up write command
;
waitio:	;enter	here from read	and write to perform the actual i/o
;	operation. return a 00h in register a if the operation completes
;	properly, and 0lh if an error occurs during the read or write
;
;	in this case, we have saved the disk number in 'diskno' (0, 1)
;			the track number in 'track' (0-76)
;			the sector number in 'sector' (1-26)
;			the dma address in 'dmaad' (0-65535)
	ds	256		;space reserved for i/o drivers
	mvi	a, 1		;error condition
	ret			;replaced when filled-in
;
;	the remainder of the cbios is reserved uninitialized
;	data area, and does not need to be a Part of the
;	system	memory image (the space must be available,
;	however, between"begdat" and"enddat").
;
track:	ds	2		;two bytes for expansion
sector:	ds	2		;two bytes for expansion
dmaad:	ds	2		;direct memory address
diskno:	ds	1		;disk number 0-15
;
;	scratch ram area for bdos use
begdat	equ	$	 	;beginning of data area
dirbf:	ds	128	 	;scratch directory area
all00:	ds	31	 	;allocation vector 0
all01:	ds	31	 	;allocation vector 1
all02:	ds	31	 	;allocation vector 2
all03:	ds	31	 	;allocation vector 3
chk00:	ds	16		;check vector 0
chk01:	ds	16		;check vector 1
chk02:	ds	16	 	;check vector 2
chk03:	ds	16	 	;check vector 3
;
enddat	equ	$	 	;end of data area
datsiz	equ	$-begdat;	;size of data area
	end
